package concurrent;

import java.util.Calendar;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * DelayQueue是一个支持延时获取元素的无界阻塞队列，里面的元素全部都是“可延期”的元素，
 * 列头的元素是最先“到期”的元素，如果队列里面没有元素到期，是不能从列头获取元素的，
 * 哪怕有元素也不行，也就是说只有在延迟期到时才能够从队列中取元素。
 *
 * @author jack.wu
 * @since 2019/12/23 13:59
 */
public class DelayQueueTest {

    static DelayQueue<Msg1> delayQueue = new DelayQueue<>();

    static {
        new Thread(() -> {
            for (; ; ) {
                Msg1 msg;
                try {
                    // 获取一条推送消息，此方法会进行阻塞，直到返回结果
                    msg = delayQueue.take();
                    long endTime = System.currentTimeMillis();
                    System.out.println(String.format("[定时发送时间：%s，实际发送时间：%s，发送消息：%s]",
                            msg.getSendTimeMs(), endTime, msg));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 推送消息
     *
     * @param priority  优先级
     * @param msg       消息
     * @param startTime 推送时间
     */
    public static void pushMsg(int priority, String msg, long startTime) {
        delayQueue.put(new Msg1(priority, msg, startTime));
    }

    public static void main(String[] args) {
        for (int i = 5; i > 1; i--) {
            String msg = "消息" + i;
            pushMsg(i, msg, System.currentTimeMillis() + i * 2000);
        }
    }

}

class Msg1 implements Delayed {

    /**
     * 优先级
     */
    private int priority;

    /**
     * 消息
     */
    private String msg;

    /**
     * 发送时间，毫秒
     */
    private long sendTimeMs;

    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public long getSendTimeMs() {
        return sendTimeMs;
    }

    public void setSendTimeMs(long sendTimeMs) {
        this.sendTimeMs = sendTimeMs;
    }

    public Msg1(int priority, String msg, long sendTimeMs) {
        this.priority = priority;
        this.msg = msg;
        this.sendTimeMs = sendTimeMs;
    }

    @Override
    public String toString() {
        return "Msg1{" +
                "priority=" + priority +
                ", msg='" + msg + '\'' +
                ", sendTimeMs=" + sendTimeMs +
                '}';
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.sendTimeMs - Calendar.getInstance().getTimeInMillis(), TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        if (o instanceof Msg1) {
            Msg1 c2 = (Msg1) o;
            return Integer.compare(this.priority, c2.priority);
        }
        return 0;
    }
}
